package com.rc.saas.mini.component;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * Redis读取器,支持自动重连接
 */
@Component
public class RedisLoader {
    @Autowired
    @Qualifier("redisTemplate")
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 写入缓存
     * @param key
     * @param value
     * @param <T>
     */
    public <T> void opsForValueSet(String key, T value, long timeout, TimeUnit unit) {
        //手动序列化
        String json = JSON.toJSONString(value);

        redisTemplate.execute(new RedisCallback<Object>() {
            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                redisTemplate.opsForValue().set(key, json, timeout, unit);
                return null;
            }
        });
    }

    /**
     * 读取缓存
     * @param key
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T opsForValueGet(String key, Class<T> clazz) {
        return redisTemplate.execute(new RedisCallback<T>() {
            @Override
            public T doInRedis(RedisConnection connection) throws DataAccessException {
                String json = (String) redisTemplate.opsForValue().get(key);
                if (StringUtils.isBlank(json)) {
                    return null;
                }

                //手动反序列化
                T obj = JSON.parseObject(json, clazz);
                return obj;
            }
        });
    }

    /**
     * 删除缓存
     * @param key
     * @return
     */
    public Boolean delete(String key) {
        return (Boolean) redisTemplate.execute(new RedisCallback<Object>() {
            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                return redisTemplate.delete(key);
            }
        });
    }

    /**
     * HASH
     * 按3天有效期写入缓存
     * @param key
     * @param field
     * @param value
     * @param <T>
     */
    public <T> void opsForHashPut(String key, String field, T value, long timeout, TimeUnit unit) {
        String json = JSON.toJSONString(value);

        redisTemplate.execute(new RedisCallback<Object>() {
            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                redisTemplate.opsForHash().put(key, field, json);
                redisTemplate.expire(key, timeout, unit);

                return null;
            }
        });
    }

    /**
     * HASH
     * 读取缓存
     * @param key
     * @param field
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T opsForHashGet(String key, String field, Class<T> clazz) {
        return redisTemplate.execute(new RedisCallback<T>() {
            @Override
            public T doInRedis(RedisConnection connection) throws DataAccessException {
                String json = (String) redisTemplate.opsForHash().get(key, field);
                if (StringUtils.isBlank(json)) {
                    return null;
                }

                T obj = JSON.parseObject(json, clazz);

                return obj;
            }
        });
    }

    /**
     * HASH
     * 删除hash某个fileld
     * @param key
     * @param field
     * @return
     */
    public Long opsForHashDelete(String key, String field) {
        return (Long) redisTemplate.execute(new RedisCallback<Object>() {
            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                return redisTemplate.opsForHash().delete(key, field);
            }
        });
    }



    public String getRedis(final String keyValue) {
        return (String) redisTemplate.execute((RedisCallback<Object>) connection -> {
            byte[] key = redisTemplate.getStringSerializer().serialize(keyValue);
            if (connection.exists(key)) {
                byte[] value = connection.get(key);
                return redisTemplate.getStringSerializer().deserialize(value);
            }
            return null;
        });
    }
}
